package com.xz.coursearrange.GA.impl;

import com.xz.coursearrange.entity.ClassTask;
import lombok.Getter;
import lombok.Setter;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

/**
 * @Description 表示一个种群或个体的一个世代，并对它们应用群组级别的操作
 */
public class Population {
    private Individual[] population;

    @Setter
    @Getter
    private double populationFitness = 0.0; // 种群的总体适应度(种群所有染色体的适应度相加)

    public Population(int populationSize) {
        this.population = new Individual[populationSize];
    }

    /**
     * 创建种群
     *
     * @param populationSize 种群最大数量
     * @param classTaskList 教学任务列表
     */
    public Population(int populationSize, List<ClassTask> classTaskList) {
        /**
         * Individual 是个体
         * 染色体：每个班的课表（40节课）
         * 基因：一节课的信息（课程+教师+属性）
         * 个体：所有班级的课表组合
         * 种群：一批不同版本的个体（课表方案）
         * 初始化：从课程任务列表生成初始课表（随机 + 固定）
         *
         * 为什么要随机生成多个课表？
         * 这是遗传算法的关键思想：
         *      一开始你不知道哪套课表好，但你给出很多“尝试版本”，通过交叉、变异、优胜劣汰，让它们自己进化出更优的结果。
         *  种群 Population
         * │
         * ├── 个体 Individual（课表1）
         * │   ├── 班A课表 → 40节课
         * │   └── 班B课表 → 40节课
         * │
         * ├── 个体 Individual（课表2）
         * │   ├── 班A课表 → 40节课（不同顺序）
         * │   └── 班B课表 → 40节课
         * │
         * └── ...
         */
        this.population = new Individual[populationSize];

        for (int individualCount = 0; individualCount < populationSize; individualCount++) {
            //构造每个 Individual个体 的染色体（课表），
            Individual individual = new Individual(classTaskList);
            this.population[individualCount] = individual;
        }
    }

    /**
     * @return 获取当前种群的所有的染色体
     */
    public Individual[] getIndividuals() {
        return this.population;
    }

    /**
     * 根据适应度排序 适应度大的在前
     * 优先选出更优秀的个体。
     * @param offset 位置
     * @return 根据位置获取该染色体的适应度
     */
    public Individual getFittest(int offset) {
        Arrays.sort(this.population, new Comparator<Individual>() {
            @Override
            public int compare(Individual o1, Individual o2) {
                if (o1.getFitness() > o2.getFitness()) {
                    return -1;
                } else if (o1.getFitness() < o2.getFitness()) {
                    return 1;
                }
                return 0;
            }
        });
        return this.population[offset];
    }

    /**
     * 获取平均适应度
     *
     * @return
     */
    public double getAvgFitness() {
        if (this.populationFitness == -1) {
            double totalFitness = 0;
            for (Individual individual : this.population) {
                totalFitness += individual.getFitness();
            }
            this.populationFitness = totalFitness;
        }
        return this.populationFitness / this.size();
    }

    /**
     * @return 种群的数量
     */
    public int size() {
        return this.population.length;
    }

    public Individual setIndividual(int offset, Individual individual) {
        return population[offset] = individual;
    }

    public Individual getIndividual(int offset) {
        return population[offset];
    }

    /**
     * 随机交换染色体位置
     */
    public void shuffle() {
        Random random = new Random();
        for (int i = population.length - 1; i > 0; i--) {
            int index = random.nextInt(i + 1);
            Individual temp = this.population[index];
            population[index] = this.population[i];
            this.population[i] = temp;
        }
    }
}
